import { locationName, uniformBuffer } from "./Interface";

interface geoData {
    shaderName: string;
    unifroms: Map<string, unifromData>;
}
interface unifromData {
    array: Float32Array;
    buffer?: GPUBuffer;
}

//材质对象
export default class Mat {
    shader: string;
    unifroms: Map<string, unifromData>;

    public constructor(data: geoData) {
        this.shader = data.shaderName;
        this.unifroms = data.unifroms;
    }

    public init(device: GPUDevice) {
        this.initUniform(device);
    }

    private initUniform(device: GPUDevice) {
        const { unifroms } = this;

        unifroms.forEach(u => {
            const { array } = u;
            const verticesBuffer = device!.createBuffer({
                //缓冲区字节长度
                size: array.byteLength,
                //设置该缓冲区的用途()
                usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
            });
            u.buffer = verticesBuffer;
        });
    }

    public update(device: GPUDevice, renderPass: GPURenderPassEncoder, locationName: Map<string, locationName>) {
        this.updateUniform(device, renderPass, locationName);
    }

    private updateUniform(device: GPUDevice, renderPass: GPURenderPassEncoder, locationName: Map<string, locationName>) {
        const { unifroms } = this;

        const bindGroup = new Map<number, { groupLayout: GPUBindGroupLayout, array: Array<GPUBindGroupEntry> }>();

        unifroms.forEach((value, key) => {
            const { array, buffer } = value;

            const location = locationName.get(key) as uniformBuffer;
            if (location) {
                device!.queue.writeBuffer(buffer!, 0, array);

                let curBindGroup = bindGroup.get(location.group);
                if (curBindGroup) {
                    curBindGroup.array.push({ binding: location.binding, resource: { buffer: buffer! } });
                } else {
                    curBindGroup = {
                        groupLayout: location.groupLayout!,
                        array: [{ binding: location.binding, resource: { buffer: buffer! } }],
                    };
                    bindGroup.set(location.group, curBindGroup)
                }

            } else {
                console.log(`[${key}没有找到对应Location]`);
            }
        });
        bindGroup.forEach((val, key) => {
            const { groupLayout, array } = val;
            const bindGroup = device.createBindGroup({
                layout: groupLayout,
                entries: array,
            });
            renderPass.setBindGroup(key, bindGroup);//这个地方大概不需要重新执行?,放在Init里面?
        })
    }

    public setData(name: string, array: Float32Array) {
        const { unifroms } = this;
        const cur = unifroms.get(name);
        if (cur) {
            cur.array = array;
        }
    }

}